package com.cloudlead.plugin.scheduler.service.impl;

import java.util.Date;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import com.cloudlead.plugin.scheduler.BusinessModules;
import com.cloudlead.plugin.scheduler.DefaultExecuteJob;
import com.cloudlead.plugin.scheduler.entity.EScheduleJob;
import com.cloudlead.plugin.scheduler.query.QScheduleJobInstance;
import com.cloudlead.plugin.scheduler.query.QScheduleJobParams;
import com.cloudlead.plugin.scheduler.repository.EScheduleJobInstanceRepository;
import com.cloudlead.plugin.scheduler.repository.EScheduleJobRepository;
import com.cloudlead.plugin.scheduler.service.ScheduleJobService;
import com.cloudlead.plugin.scheduler.vo.ScheduleJob;
import com.cloudlead.plugin.scheduler.vo.dict.JobStatus;
import com.cloudlead.plugin.scheduler.ScheduleJobSchedulerListener;
import com.cloudlead.plugin.scheduler.query.QScheduleJob;
import com.cloudlead.utils.scheduler.JobMetadata;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cloudlead.common.lang.annotation.Label;
import com.cloudlead.common.lang.exception.RequestNotAcceptableException;
import com.cloudlead.common.lang.exception.ResourceNotFoundException;
import com.cloudlead.common.persistence.impl.AbstractMultiTableCrudService;
import com.cloudlead.utils.scheduler.ScheduledTaskService;
import com.cloudlead.plugin.scheduler.ScheduleJobListener;
import com.cloudlead.plugin.scheduler.repository.EScheduleJobParamsRepository;
import org.springframework.transaction.annotation.Transactional;

/**
 * ScheduleJobServiceImpl is a Codegen service implement type
 */
@Label("计划任务服务实现")
@Service("scheduleJobService")
public class ScheduleJobServiceImpl
        extends
        AbstractMultiTableCrudService<EScheduleJobRepository, ScheduleJob, EScheduleJob>
        implements ScheduleJobService {

    @Autowired
    private ScheduledTaskService scheduledTaskService;

    @Autowired
    private EScheduleJobInstanceRepository scheduleJobInstanceRepository;

    @Autowired
    private EScheduleJobParamsRepository scheduleJobParamsRepository;

    @Autowired
    public ScheduleJobServiceImpl(EScheduleJobRepository repository) {
        super(BusinessModules.ScheduleJob, repository);
    }

    @PostConstruct
    public void init() {
        logger.debug("Schedule job service starting...");
        // 启动计划任务服务
        scheduledTaskService.start();

        scheduledTaskService
                .addSchedulerListener(new ScheduleJobSchedulerListener(this));

        // 添加任务执行状态监听器
        scheduledTaskService.addJobListener(new ScheduleJobListener());

        // TODO:同步状态
        //处理异常暂停的任务
        Set<JobMetadata> jobMetadatas = scheduledTaskService.listJobMetadata(CLOUDLEAD_SCHEDULE_JOB_GROUP, null, Trigger.TriggerState.PAUSED);
        for (JobMetadata jobMetadata : jobMetadatas) {
            EScheduleJob scheduleJob = this.repository.findOne(QScheduleJob.scheduleJob.name.eq(jobMetadata.getName()));
            if (JobStatus.enabled.name().equals(scheduleJob.getStatus())) {
                scheduledTaskService.resumeJob(jobMetadata.getName(), jobMetadata.getGroup());
            }
        }
    }

    private void createScheduledTask(ScheduleJob jobTask) {
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put(SCHEDULE_JOB_PARAM, jobTask);
        JobKey jobKey = scheduledTaskService.addJob(DefaultExecuteJob.class,
                jobTask.getName(), CLOUDLEAD_SCHEDULE_JOB_GROUP, jobDataMap,
                jobTask.getCron(), null == jobTask.getStartTime() ? null
                        : new Date(jobTask.getStartTime()), null == jobTask
                        .getEndTime() ? null : new Date(jobTask.getEndTime()));
        jobTask.setName(jobKey.getName());
    }

    private void deleteScheduledTask(ScheduleJob jobTask) {
        scheduledTaskService.deleteJob(jobTask.getName(),
                CLOUDLEAD_SCHEDULE_JOB_GROUP);
    }

    private void pauseScheduledTask(ScheduleJob jobTask) {
        scheduledTaskService.pauseJob(jobTask.getName(),
                CLOUDLEAD_SCHEDULE_JOB_GROUP);
    }

    private void resumeScheduledTask(ScheduleJob jobTask) {
        scheduledTaskService.resumeJob(jobTask.getName(),
                CLOUDLEAD_SCHEDULE_JOB_GROUP);
    }

    @Override
    @Transactional
    public void create(ScheduleJob vo) {
        vo.setStatus(JobStatus.initialized);
        super.create(vo);
    }

    @Override
    @Transactional
    public void delete(String id) {
        ScheduleJob vo = view(id);
        deleteScheduledTask(vo);

        scheduleJobInstanceRepository
                .deleteAll(QScheduleJobInstance.scheduleJobInstance.jobId
                        .eq(id));
        scheduleJobParamsRepository
                .deleteAll(QScheduleJobParams.scheduleJobParams.jobId
                        .eq(id));
        super.delete(id);
    }

    @PreDestroy
    public void destroy() {
        logger.debug("Schedule job service stopped.");
        // 停止计划任务服务
        scheduledTaskService.stop();
    }

    @Override
    @Transactional
    public void updateScheduleJobStart(String id) {
        ScheduleJob job = view(id);
        if (null == job) {
            throw new ResourceNotFoundException("schedule job [" + id
                    + "] not found.");
        }
        if (!JobStatus.initialized.equals(job.getStatus())
                && !JobStatus.disabled.equals(job.getStatus())) {
            throw new RequestNotAcceptableException("schedule job stauts is "
                    + job.getStatus() + ", can't start");
        }
        createScheduledTask(job);
    }

    @Override
    @Transactional
    public void updateScheduleJobStop(String id) {
        ScheduleJob job = view(id);
        if (null == job) {
            throw new ResourceNotFoundException("schedule job [" + id
                    + "] not found.");
        }
        if (!JobStatus.enabled.equals(job.getStatus())) {
            throw new RequestNotAcceptableException("schedule job stauts is "
                    + job.getStatus() + ", can't stop");
        }
        deleteScheduledTask(job);
    }

    @Override
    @Transactional
    public void updateScheduleJobPause(String id) {
        ScheduleJob job = view(id);
        if (null == job) {
            throw new ResourceNotFoundException("schedule job [" + id
                    + "] not found.");
        }
        if (!JobStatus.enabled.equals(job.getStatus())) {
            throw new RequestNotAcceptableException("schedule job stauts is "
                    + job.getStatus() + ", can't pause");
        }
        pauseScheduledTask(job);
    }

    @Override
    @Transactional
    public void updateScheduleJobResume(String id) {
        ScheduleJob job = view(id);
        if (null == job) {
            throw new ResourceNotFoundException("schedule job [" + id
                    + "] not found.");
        }
        if (!JobStatus.paused.equals(job.getStatus())) {
            throw new RequestNotAcceptableException("schedule job stauts is "
                    + job.getStatus() + ", can't resume");
        }
        resumeScheduledTask(job);
    }

}
